﻿using System;
using System.Collections.Generic;

namespace Sliver.Core.Event
{
    public class EventManager
    {
        protected static readonly Dictionary<string, object> Callbacks = new Dictionary<string, object>();

        public static void Listen(string key, Action callback)
        {
            if (Callbacks.ContainsKey(key))
            {
                List<Action> actions = (List<Action>) Callbacks[key];
                actions.Add(callback);
            }
            else
            {
                Callbacks.Add(key, new List<Action>() {callback});
            }
        }

        public static void Listen<T1>(string key, Action<T1> callback)
        {
            if (Callbacks.ContainsKey(key))
            {
                List<Action<T1>> actions = (List<Action<T1>>) Callbacks[key];
                actions.Add(callback);
            }
            else
            {
                Callbacks.Add(key, new List<Action<T1>>() {callback});
            }
        }

        public static void Listen<T1, T2>(string key, Action<T1, T2> callback)
        {
            if (Callbacks.ContainsKey(key))
            {
                List<Action<T1, T2>> actions = (List<Action<T1, T2>>) Callbacks[key];
                actions.Add(callback);
            }
            else
            {
                Callbacks.Add(key, new List<Action<T1, T2>>() {callback});
            }
        }

        public static void Listen<T1, T2, T3>(string key, Action<T1, T2, T3> callback)
        {
            if (Callbacks.ContainsKey(key))
            {
                List<Action<T1, T2, T3>> actions = (List<Action<T1, T2, T3>>) Callbacks[key];
                actions.Add(callback);
            }
            else
            {
                Callbacks.Add(key, new List<Action<T1, T2, T3>>() {callback});
            }
        }

        public static void Remove(string key, Action callback)
        {
            if (!Callbacks.ContainsKey(key)) return;
            List<Action> actions = (List<Action>) Callbacks[key];
            actions.Remove(callback);
            if (actions.Count == 0) Callbacks.Remove(key);
        }

        public static void Remove<T1>(string key, Action<T1> callback)
        {
            if (!Callbacks.ContainsKey(key)) return;
            List<Action<T1>> actions = (List<Action<T1>>) Callbacks[key];
            actions.Remove(callback);
            if (actions.Count == 0) Callbacks.Remove(key);
        }

        public static void Remove<T1, T2>(string key, Action<T1, T2> callback)
        {
            if (!Callbacks.ContainsKey(key)) return;
            List<Action<T1, T2>> actions = (List<Action<T1, T2>>)Callbacks[key];
            actions.Remove(callback);
            if (actions.Count == 0) Callbacks.Remove(key);
        }

        public static void Remove<T1, T2, T3>(string key, Action<T1, T2, T3> callback)
        {
            if (!Callbacks.ContainsKey(key)) return;
            List<Action<T1, T2, T3>> actions = (List<Action<T1, T2, T3>>)Callbacks[key];
            actions.Remove(callback);
            if (actions.Count == 0) Callbacks.Remove(key);
        }

        public static void Remove(string key)
        {
            if (Callbacks.ContainsKey(key)) Callbacks.Remove(key);
        }
        
        public static void RemoveAll()
        {
            Callbacks.Clear();
        }

        public static void Emit(string key)
        {
            if (Callbacks.ContainsKey(key))
            {
                List<Action> actions = (List<Action>) Callbacks[key];
                foreach (Action action in actions)
                {
                    action.Invoke();
                }
            }
        }

        public static void Emit<T1>(string key, T1 param1)
        {
            if (Callbacks.ContainsKey(key))
            {
                List<Action<T1>> actions = (List<Action<T1>>)Callbacks[key];
                foreach (Action<T1> action in actions)
                {
                    action.Invoke(param1);
                }
            }
        }

        public static void Emit<T1, T2>(string key, T1 param1, T2 param2)
        {
            if (Callbacks.ContainsKey(key))
            {
                List<Action<T1, T2>> actions = (List<Action<T1, T2>>)Callbacks[key];
                foreach (Action<T1, T2> action in actions)
                {
                    action.Invoke(param1, param2);
                }
            }
        }

        public static void Emit<T1, T2, T3>(string key, T1 param1, T2 param2, T3 param3)
        {
            if (Callbacks.ContainsKey(key))
            {
                List<Action<T1, T2, T3>> actions = (List<Action<T1, T2, T3>>)Callbacks[key];
                foreach (Action<T1, T2, T3> action in actions)
                {
                    action.Invoke(param1, param2, param3);
                }
            }
        }
    }
}